package ads.server;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.log4j.Logger;

import spread.SpreadException;
import spread.SpreadMessage;
import ads.exception.InvalideInvokerException;
import ads.exception.SpreadRemoteException;

public class SpreadInvokerThread extends Thread {
	private SpreadRequestMessage msg;
	private SpreadMember spreadMember;
	private SpreadMemberRemoteInterface proxy;
	private static final Logger log = Logger
			.getLogger(SpreadInvokerThread.class.getName());

	public SpreadInvokerThread(SpreadMember spreadMember,
			SpreadRequestMessage msg) {
		super();
		this.spreadMember = spreadMember;
		this.msg = msg;
	}

	@Override
	public void run() {
		// try {
		invoke();
		// } catch (SpreadRemoteException e) {
		// e.printStackTrace();
		// }
	}

	private void invoke() {
		log.debug("handle invoke form message:" + msg);
		Object response = null;
		String msgID = msg.getId();
		String methodName = msg.getMethod();
		Class[] classz = null;
		Object[] args = null;
		if (msg.getArgs() != null) {
			args = msg.getArgs();
			classz = new Class[args.length];
			for (int i = 0; i < classz.length; i++) {
				classz[i] = args[i].getClass();
			}
		}
		try {
			Method method = spreadMember.getClass().getMethod(methodName,
					classz);
			response = method.invoke(spreadMember, args);
			if (response != null && !(response instanceof Serializable)) {
				String errMsg = "argument type "
						+ response.getClass().getCanonicalName()
						+ " is not Serializable";
				response = new SpreadRemoteException(errMsg);
				log.debug(errMsg);
			}
			log.debug("method " + method.toString() + " return " + response);
			if (method.getReturnType().equals(Void.TYPE)) {
				log.debug("method " + method.toString() + "has no response ");
				return;
			}
		} catch (NoSuchMethodException e) {
			log.debug(e);
			response = new SpreadRemoteException(e);
		} catch (IllegalArgumentException e) {
			log.debug(e);
			response = new SpreadRemoteException(e);
		} catch (IllegalAccessException e) {
			log.debug(e);
			response = new SpreadRemoteException(e);
		} catch (InvocationTargetException e) {
			log.debug(e);
			if (e.getTargetException() instanceof InvalideInvokerException) {
				log.debug("this  invoke of Method " + methodName
						+ " should not be handled by this member ");
				return;
			}
			response = new SpreadRemoteException(e);
		}
		try {
			if (response == null || response instanceof Serializable) {
				Serializable sr = (Serializable) response;
				SpreadResponseMessage data = new SpreadResponseMessage(msgID,
						sr);
				SpreadMessage message = new SpreadMessage();
				message.addGroup(spreadMember.config.getGroupName());
				message.setFifo();
				message.setObject(data);
				spreadMember.connection.multicast(message);
				log.debug("Invoke of Method " + methodName + " sent response"
						+ data);
			}
		} catch (SpreadException e) {
			e.printStackTrace();
		}
	}
}
